#include <fstream>
#include <sstream>
#include <istream>
#include <algorithm>
#include <stdexcept>
#include <vector>
#include <deque>
#include <string>
#include <iostream>
#include <iomanip>


#include <boost/regex.hpp>

#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <portable_timer.h>
#include <progress_indicator.h>
#define _MY_STL_MACROS
#include <stlhelper.h>
#include <ultoa.h>
#include <perlutil.h>
#include <print_error.h>
#include <index_string.h>
#include <glob_files.h>
#include <open_fstream.h>
#include <get_filename.h>
#include <seq_pairs.h>
#include <crc.h>
#include <digest.h>
#include "get_arg.h"


using std::vector;
using std::deque;
using std::ofstream;
using std::ifstream;
using std::istream;
using std::istringstream;
using std::ostream;
using std::string;
using std::runtime_error;
using std::cerr;
using std::cin;
using std::cout;
using boost::regex;
using boost::match_results;
using boost::regex_search;


unsigned regex_search_in_str(const std::string& str, boost::regex& regex, unsigned match_flag)
{
	if (boost::regex_search(str, regex, boost::match_default))
		return match_flag;
	return 0;
}

//________________________________________________________________________________________

//		do_parse_pairs

//________________________________________________________________________________________
struct do_parse_pairs
{
private:
	std::string				comment_letters;
public:                     
	t_program_args&			args;
	unsigned				cnt_matching_lines;
	unsigned				cnt_all_lines;
	unsigned				cnt_regex_no_match;
	boost::regex 			regex1;
	boost::regex 			regex2;
	bool					identical;
	do_parse_pairs( 
					t_program_args&					args_,
					const std::string&				comment_letters_):
			comment_letters(comment_letters_),
			args(args_),
			cnt_matching_lines(0),
			cnt_regex_no_match(0),
			regex1(args.regex),
			regex2(args.alt_regex),
			identical(args.regex == args.alt_regex)
			{}
	void operator()(istream& is, unsigned cnt_line)
	{
		// get data for one protein pair
		string name1, name2;

		// comment if false
		string comment_line;
		if (!seq_pairs::parse_ids(is, name1, name2, comment_line, comment_letters,
								  seq_pairs::ePARSE_IDS_ONLY))
		{
			if (comment_line != "\n")
			{
				cout	<< comment_line;
			}
			return;
		}		

		cnt_all_lines = cnt_line;

		string line;
		if (is.peek() == '\t')
		{
			getline(is, line);
			if (!is)
				throw std::runtime_error("The data is not in the correct format");
			is.putback('\n');
		}

		// one must match one regex, and the other match the other regex
		// use flags: 1 = match regex1, 2 = match regex2
		// use flags: 4 = match name1, 8 = match name2
		unsigned matches = 0;
		matches |= regex_search_in_str(name1, regex1, 1+4);
		matches |= regex_search_in_str(name2, regex2, 2+8);
		if (matches != 15)
		{
			matches |= regex_search_in_str(name2, regex1, 1+8);
			matches |= regex_search_in_str(name1, regex2, 2+4);
		}

		// make sure the regex matches
		string match1, match2;
		if (matches != 15)
		{	
			++cnt_regex_no_match;
			return;
		}
		cout << name1 << "\t" << name2;
		if (!args.ids_only)
			cout << line;
		cout << "\n";
		++cnt_matching_lines;
	}
};







int main(int argc, char* argv[])
{
	t_program_args args;

	try
	{

	debug_func_cerr(5);

	// don't use C streams
	std::ios::sync_with_stdio(false);


	// get command line arguments
	if (!process_command_line_options(argc, argv, args))
		return 1;



	// surround by parenthesis if not present
	args.VERBOSE(2) << "\tThe regular expression used to match identifiers will be \"" +
						args.regex + "\"\n";
	if (args.regex != args.alt_regex)
		args.VERBOSE(2) << "\tThe regular expression used to match the other identifier will be \"" +
							args.alt_regex + "\"\n";

	//
	//	print matching
	//
	string file_name = args.file_input.length() ? 
						 get_filename(args.file_input) : 
						 "STDIN";
	args.VERBOSE() << "\tReading sequence pair data from [" + file_name + "]\n";
	do_parse_pairs parse_pairs(args, args.comment_letters);
	seq_pairs::read_data(parse_pairs, args.file_input, args.VERBOSE());
	args.VERBOSE(1) << "\t\t" << parse_pairs.cnt_all_lines
					<< " lines read from [" << file_name << "].\n";
	if (parse_pairs.cnt_regex_no_match)
		args.VERBOSE(1) << "\t\t" << parse_pairs.cnt_regex_no_match
						<< " lines without any regular expression matches.\n";
	args.VERBOSE(1) << "\t\t" << parse_pairs.cnt_matching_lines
					<< " lines with matching identifiers.\n";





	args.VERBOSE() << "\tAll finished.\n";

	}
	catch (std::exception& e)
	{
		std_print_error(args.CERR(), e.what());
		return 1;
	}

	return 0;
}

